package com.aac.rabbitrfc.service.impl;

import com.aac.rabbitrfc.constant.SAPConstant;
import com.aac.rabbitrfc.manager.RfcManager;
import com.aac.rabbitrfc.pojo.DatApplication;
import com.aac.rabbitrfc.service.BpmToSapService;
import com.aac.rabbitrfc.service.DatApplicationService;
import com.aac.rabbitrfc.service.DatDocumentService;
import com.sap.conn.jco.*;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 方法详细注释在BpmToSapService接口中
 */
@Service
@SuppressWarnings("unchecked")
public class BpmToSapServiceImpl implements BpmToSapService {

    @Autowired
    private DatApplicationService datApplicationService;

    @Autowired
    private DatDocumentService datDocumentService;

    @Override
    public Map<String, Object> getSapJson(Map<String, Object> requestMap) {
        Map<String, Object> responseMap = new HashMap<>();
        try {
            RfcManager rfcManager = getRfcManager(requestMap);
            JCoDestination destination = rfcManager.getDestination();
            String functionName = (String) requestMap.get("functionName");
            JCoFunction function = rfcManager.getFunction(destination, functionName);
            Map<String, String> inputParamMap = (Map<String, String>) requestMap.get("inputParamMap");
            Map<String, Map<String, String>> inputTableMap = (Map<String, Map<String, String>>) requestMap.get("inputTableMap");
            Map<String, List<String>> outputTableMap = (Map<String, List<String>>) requestMap.get("outputTableMap");
            List<String> outputParamNameList = (List<String>) requestMap.get("outputParamNameList");
            String inputType = null;
            String outputType = null;
            // 多一段关于输入类型的判断和赋值，使得不同输入输出类型的组合下的逻辑处理更清晰，增强代码可读性。
            // normal表示SAP入参/出参为普通类型，table表示SAP入参/出参为表类型
            if (inputParamMap != null && inputTableMap == null) {
                inputType = "normal";
            } else if (inputParamMap == null && inputTableMap != null) {
                inputType = "table";
            }
            if (outputParamNameList != null && outputTableMap == null) {
                outputType = "normal";
            } else if (outputParamNameList == null && outputTableMap != null) {
                outputType = "table";
            }
            JCoParameterList importParameterList = function.getImportParameterList();
            JCoParameterList tableParameterList = function.getTableParameterList();
            if (StringUtils.equals(inputType, "normal") &&
                    StringUtils.equals(outputType, "normal")) {
                setNormalInput(inputParamMap, importParameterList);
                function.execute(destination);
                setNormalOutput(responseMap, outputParamNameList, function);
            } else if (StringUtils.equals(inputType, "normal") &&
                    StringUtils.equals(outputType, "table")) {
                setNormalInput(inputParamMap, importParameterList);
                function.execute(destination);
                setTableOutput(responseMap, outputTableMap, function);
            } else if (StringUtils.equals(inputType, "table") &&
                    StringUtils.equals(outputType, "normal")) {
                setTableInput(inputTableMap, tableParameterList);
                function.execute(destination);
                setNormalOutput(responseMap, outputParamNameList, function);
            } else if (StringUtils.equals(inputType, "table") &&
                    StringUtils.equals(outputType, "table")) {
                setTableInput(inputTableMap, tableParameterList);
                function.execute(destination);
                setTableOutput(responseMap, outputTableMap, function);
            } else {
                responseMap.put("message", "输入输出类型组合不正确");
                return responseMap;
            }
            responseMap.put("message", "success");
        } catch (Exception e) {
            e.printStackTrace();
            responseMap.put("error", e.getMessage());
            responseMap.put("message", "fail");
        }
        return responseMap;
    }

    @Override
    public RfcManager getRfcManager(Map<String, Object> map) throws Exception {
        RfcManager rfcManager = null;
        if (map.containsKey("searchKey")) {
            String searchKey = (String) map.get("searchKey");
            if (StringUtils.isEmpty(searchKey)) {
                searchKey = SAPConstant.DEFAULT_SEARCH_KEY;
            }
            rfcManager = RfcManager.getInstance(getSAPConfigBySearchKey(searchKey));
        } else if (map.containsKey("client")) {
            String client = (String) map.get("client");
            if (StringUtils.isEmpty(client)) {
                client = SAPConstant.DEFAULT_CLIENT;
            }
            rfcManager = RfcManager.getInstance(getSAPConfigByClient(client));
        }
        return rfcManager;
    }

    public JSONObject getSAPConfigBySearchKey(String searchKey) {
        return getSAPConfig("SearchKey", searchKey);
    }

    public JSONObject getSAPConfigByClient(String client) {
        return getSAPConfig("client", client);
    }

    public JSONObject getSAPConfig(String name, String value) {
        DatApplication dat = datApplicationService.getDatApplicationByName("SystemMG");
        Map<String, Object> config = datDocumentService.getDocumentByField(dat.getAppId(), "SAPConfig", name, value);
        Set<String> keys = config.keySet();
        Iterator<String> iterator = keys.iterator();
        JSONObject SAPConfig = new JSONObject();
        while (iterator.hasNext()) {
            String key = iterator.next();
            SAPConfig.put(key, config.get(key).toString());
        }
        return SAPConfig;
    }

    public void setNormalInput(Map<String, String> inputParamMap, JCoParameterList importParameterList) {
        Set<String> inputParamNameSet = inputParamMap.keySet();
        for (String inputParamName : inputParamNameSet) {
            if (StringUtils.isNotEmpty(inputParamName)) {
                importParameterList.setValue(inputParamName, inputParamMap.get(inputParamName));
            }
        }
    }

    public void setTableInput(Map<String, Map<String, String>> inputTableMap, JCoParameterList tableParameterList) {
        int index = 0;
        Set<String> tableNameSet = inputTableMap.keySet();
        for (String tableName : tableNameSet) {
            JCoTable table = tableParameterList.getTable(tableName);
            table.appendRow();
            table.setRow(index);
            index++;
            Map<String, String> paramMap = inputTableMap.get(tableName);
            Set<String> paramNameSet = paramMap.keySet();
            for (String paramName : paramNameSet) {
                table.setValue(paramName, paramMap.get(paramName));
            }
        }
    }

    public void setNormalOutput(Map<String, Object> result, List<String> outputParamNameList, JCoFunction function) {
        JCoParameterList exportParameterList = function.getExportParameterList();
        Map<String, String> responseOutputParamMap = new HashMap<>();
        if (outputParamNameList.isEmpty()) {
            for (JCoField jCoField : exportParameterList) {
                responseOutputParamMap.put(jCoField.getName(), jCoField.getValue().toString());
            }
        } else {
            for (String outputParamName : outputParamNameList) {
                responseOutputParamMap.put(outputParamName, exportParameterList.getString(outputParamName));
            }
        }
        result.put("responseOutputParamMap", responseOutputParamMap);
    }

    public void setTableOutput(Map<String, Object> result, Map<String, List<String>> outputTableMap, JCoFunction function) {
        JCoParameterList tableParameterList = function.getTableParameterList();
        Map<String, List<Map<String, String>>> responseOutputParamMap = new HashMap<>();
        List<Map<String, String>> responseOutputParamMapList = new ArrayList<>();
        if (outputTableMap != null) {
            for (String outputTableName : outputTableMap.keySet()) {
                JCoTable table = tableParameterList.getTable(outputTableName);
                List<String> outputParamNameList = outputTableMap.get(outputTableName);
                for (int i = 0; i < table.getNumRows(); i++) {
                    Map<String, String> outputParamMap = new HashMap<>();
                    table.setRow(i);
                    if (outputParamNameList.isEmpty()) {
                        for (JCoField jCoField : table) {
                            outputParamMap.put(jCoField.getName(), jCoField.getValue().toString());
                        }
                    } else {
                        for (String outputParamName : outputParamNameList) {
                            outputParamMap.put(outputParamName, table.getString(outputParamName));
                        }
                    }
                    responseOutputParamMapList.add(outputParamMap);
                }
                responseOutputParamMap.put(outputTableName, responseOutputParamMapList);
            }
        }
        result.put("responseOutputTableMap", responseOutputParamMap);
    }

}
